package com.yy.QSManage.tool;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yy.QSManage.enums.ErrorCodeEnum;
import com.yy.QSManage.exception.ServiceException;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

public class TreeUtil implements Serializable {
    private static final String ID = "id";
    private static final String PID = "pid";
    private static final String IS_DELETE = "is_delete";
    private static final String STATE = "state";

    public TreeUtil() {
    }

    public static <T extends TreeNode<T>> List<T> build(List<T> treeNodes, String pid) {
        List<T> treeList = new ArrayList();
        Iterator var3 = treeNodes.iterator();

        while(var3.hasNext()) {
            T treeNode = (T) var3.next();
            if (pid.equals(treeNode.getPid())) {
                treeList.add(findChildren(treeNodes, treeNode));
            }
        }

        return treeList;
    }

    public static <T extends TreeNode> List<T> build(List<T> treeNodes) {
        List<T> result = new ArrayList();
        Map<String, T> nodeMap = new LinkedHashMap(treeNodes.size());
        Iterator var3 = treeNodes.iterator();

        TreeNode node;
        while(var3.hasNext()) {
            node = (TreeNode)var3.next();
            nodeMap.put(node.getId(), (T) node);
        }

        var3 = nodeMap.values().iterator();

        while(true) {
            while(var3.hasNext()) {
                node = (TreeNode)var3.next();
                String nodePid = node.getPid();
                T parent = nodeMap.get(nodePid);
                String nodeId = node.getId();
                if (parent != null && !nodeId.equals(parent.getId())) {
                    parent.getChildren().add((T) node);
                } else {
                    result.add((T) node);
                }
            }

            return result;
        }
    }

    private static <T extends TreeNode<T>> T findChildren(List<T> treeNodes, T rootNode) {
        Iterator var2 = treeNodes.iterator();

        while(var2.hasNext()) {
            T treeNode = (T) var2.next();
            if (rootNode.getId().equals(treeNode.getPid())) {
                rootNode.getChildren().add(findChildren(treeNodes, treeNode));
            }
        }

        return rootNode;
    }

    public static <T extends TreeNode<T>> List<String> findChildrenIdList(IService<T> service, String sId, List<String> ids, Integer isDel, Integer state) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        ((QueryWrapper)queryWrapper.eq(state != null, "state", state)).eq(isDel != null, "is_delete", isDel);
        if (null == sId) {
            queryWrapper.isNull("pid");
        } else {
            queryWrapper.eq("pid", sId);
        }

        List<T> list = service.list(queryWrapper);
        if (null != list && list.size() > 0) {
            List<String> idList = (List)list.stream().map(TreeNode::getId).collect(Collectors.toList());
            if (idList.size() > 0) {
                ids.addAll(idList);
                idList.forEach((id) -> {
                    findChildrenIdList(service, id, ids, isDel, state);
                });
            }
        }

        return ids;
    }

    public static <T extends TreeNode<T>> List<String> findChildrenIdList(IService<T> service, String sId, List<String> ids, Integer isDel, Integer state, String lastSql) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        ((QueryWrapper)queryWrapper.eq(state != null, "state", state)).eq(isDel != null, "is_delete", isDel);
        if (null == sId) {
            queryWrapper.isNull("pid");
        } else {
            queryWrapper.eq("pid", sId);
        }

        if (StrUtil.isNotBlank(lastSql)) {
            queryWrapper.last(lastSql);
        }

        List<T> list = service.list(queryWrapper);
        if (null != list && list.size() > 0) {
            List<String> idList = list.stream().map(TreeNode::getId).collect(Collectors.toList());
            if (idList.size() > 0) {
                ids.addAll(idList);
                idList.forEach((id) -> {
                    findChildrenIdList(service, id, ids, isDel, state, lastSql);
                });
            }
        }

        return ids;
    }

    public static <T extends TreeNode<T>> T getRoot(IService<T> service, String sId) {
        T t = (T) service.getById(sId);
        if (t == null) {
            throw new ServiceException(ErrorCodeEnum.PARENT_NTO_EXIST, false);
        } else {
            String pid = t.getPid();
            if (StrUtil.isBlank(pid)) {
                return t;
            } else {
                QueryWrapper<T> queryWrapper = new QueryWrapper();
                queryWrapper.eq("id", pid);
                T parentNode = service.getOne(queryWrapper);
                if (parentNode != null) {
                    String parentNodePid = parentNode.getPid();
                    return StrUtil.isBlank(parentNodePid) ? parentNode : getRoot(service, parentNode.getId());
                } else {
                    throw new ServiceException(ErrorCodeEnum.PARENT_NTO_EXIST, false);
                }
            }
        }
    }

    public static <T extends TreeNode<T>> List<T> treeListChildren(IService<T> service, String sId, Integer isDel, Integer state) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        ((QueryWrapper)queryWrapper.eq(state != null, "state", state)).eq(isDel != null, "is_delete", isDel);
        if (StrUtil.isBlank(sId)) {
            queryWrapper.isNull("pid");
        } else {
            queryWrapper.eq("pid", sId);
        }

        List<T> list = service.list(queryWrapper);
        if (null != list && list.size() > 0) {
            Iterator var6 = list.iterator();

            while(var6.hasNext()) {
                T t = (T) var6.next();
                String id = t.getId();
                List<T> childrenList = treeListChildren(service, id, isDel, state);
                t.setChildren(childrenList);
            }
        }

        return list;
    }

    public static <T extends TreeNode<T>> List<T> treeListChildren(IService<T> service, String sId, Integer isDel, Integer state, String lastSql) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        ((QueryWrapper)queryWrapper.eq(state != null, "state", state)).eq(isDel != null, "is_delete", isDel);
        if (StrUtil.isBlank(sId)) {
            queryWrapper.isNull("pid");
        } else {
            queryWrapper.eq("pid", sId);
        }

        if (StrUtil.isNotBlank(lastSql)) {
            queryWrapper.last(lastSql);
        }

        List<T> list = service.list(queryWrapper);
        if (null != list && list.size() > 0) {
            Iterator var7 = list.iterator();

            while(var7.hasNext()) {
                T t = (T) var7.next();
                String id = t.getId();
                List<T> childrenList = treeListChildren(service, id, isDel, state, lastSql);
                t.setChildren(childrenList);
            }
        }

        return list;
    }

    public static <T extends TreeNode<T>> List<T> treeListChildrenContainSelf(IService<T> service, String sId, Integer isDel, Integer state) {
        List<T> treeList = new ArrayList();
        List<T> treeListChildren = treeListChildren(service, sId, isDel, state);
        if (StrUtil.isBlank(sId)) {
            return treeListChildren;
        } else {
            T t = service.getById(sId);
            if (null != t) {
                t.setChildren(treeListChildren);
            }

            treeList.add(t);
            return treeList;
        }
    }

    public static <T extends TreeNode<T>> void setParentIds(IService<T> service, T t) {
        String id = t.getId();
        List<String> parentIds = new ArrayList();
        String pid = t.getPid();
        if (StrUtil.isNotBlank(pid)) {
            List<String> parentIdList = getParentIdList(service, pid, parentIds);
            Collections.reverse(parentIdList);
            t.setParentIds(parentIdList);
        } else {
            t.setParentIds(parentIds);
        }

    }

    public static <T extends TreeNode<T>> List<String> getParentIds(IService<T> service, String id) {
        T t = service.getById(id);
        List<String> parentIds = new ArrayList();
        parentIds.add(id);
        String pid = t.getPid();
        if (StrUtil.isNotBlank(pid)) {
            List<String> parentIdList = getParentIdList(service, pid, parentIds);
            Collections.reverse(parentIdList);
            return parentIdList;
        } else {
            return parentIds;
        }
    }

    private static <T extends TreeNode<T>> List<String> getParentIdList(IService<T> service, String id, List<String> list) {
        if (StrUtil.isNotBlank(id)) {
            T t = service.getById(id);
            if (null != t) {
                list.add(id);
                return getParentIdList(service, t.getPid(), list);
            }
        }

        return list;
    }

    /**
     * 拼接树状表格字段路径
     * 向上拼接
     * @param service 服务类实例
     * @param field 拼接字段
     * @param subId 拼接开始层id
     * @return
     * @param <T>
     */
    public static <T extends TreeNode<T>> String jointPath(IService<T> service,String field, String subId){
        // 仓库路径组合
        List<String> parentIds = TreeUtil.getParentIds(service, subId);
        // listByIds结果无序
        List<T> faCfGoodsWarehouses = service.listByIds(parentIds);
        StringBuilder path = new StringBuilder();
        for (String id : parentIds) {
            for (T t : faCfGoodsWarehouses) {
                if (id.equals(t.getId())) {
                    path.append("/").append(ReflectUtil.getFieldValue(t, field));
                    break;
                }
            }
        }
        path = new StringBuilder(path.substring(1));
        return path.toString();
    }
}

